package values.skill
{
	import core.manager.battle.BattleManager;
	
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.utils.getDefinitionByName;
	
	import isoengine.values.MapSkillRangeList;
	import isoengine.values.MapSkillRangeValue;
	
	import mapengine.avatars.IGameAvatar;
	
	import values.avatar.AvatarCampTypeKey;
	import values.avatar.IAvatarValue;
	import values.avatar.IPropertyProvider;
	import values.events.AvatarValueEvent;

	CanNotActionBuffDebuffEffectValue;
	CanNotMoveBuffDebuffValue;
	CanNotUseSkillBuffDebuffValue;
	CanNotUseUltimate;
	HurtMeAdditinalEffectValue;
	HurtRondomAdditinalEffectValue;
	HurtRoundBuffDebuffValue;
	JudgeDeadAdditinalEffectValue;
	LogicEffectValue;
	AddHpAdditinalEffectValue;
	ImmediateEffectValue;
	BaseDamageValue;
	BuffDebuffEffectValue;
	AdditionalEffectValue;
	
	public class SkillValue extends EventDispatcher implements ISkillValue ,  IPropertyProvider
	{
		public function SkillValue()
		{
			super();
		}
		
		public function get key():String
		{
			return template.key;
		}
		
		protected var _slot:int;
		
		public function get slot():int
		{
			return _slot;
		}
		
		protected var _isUnLocked:Boolean = false;
		
		public function get isUnLocked():Boolean
		{
			return _isUnLocked;
		}
		
		public function set isUnLocked(value:Boolean):void
		{
			_isUnLocked = value;
		}
		
		protected var _owner:IAvatarValue;
		
		public function get owner():IAvatarValue
		{
			return _owner;
		}
		
		public function set owner(value:IAvatarValue):void
		{
			_owner = value;
		}
		
		protected var _mpCost:int;
		
		public function get mpCost():int
		{
			return _mpCost;
		}
		
		protected var _rangeKey:String;
		
		public function get range():MapSkillRangeValue
		{
			return MapSkillRangeList.getSkillRangeByKey(_rangeKey);
		}
		
		protected var _distance:int;

		public function get distance():int
		{
			return _distance;
		}
		
		protected var _coolingRound:int = -1;
		
		public function get coolingRound():int
		{
			return _coolingRound;
		}
		
		public function get nextUseRound():int
		{
			return Math.max( 0 , _coolingRound - BattleManager.battleManager.currentRound - _lastUseRound);
		}
		
		protected var _lastUseRound:int = 0;
		
		public function canUseSkill():Boolean
		{
			if(!isUltimateSkill && owner.debuff && ( !owner.debuff.canUseSkill )) return false;
			if(!isUltimateSkill && owner.mp < mpCost) return false;
			if(isUltimateSkill)
			{
				if(owner.debuff && !owner.debuff.canUseUltimate) return false;
				if(useCount == 0) return false;
				if(BattleManager.battleManager.currentRound - _lastUseRound < _coolingRound) return false;
			}
			
			return true;
		}
		
		public function get template():SkillTemplateValue
		{
			return _template;
		}
		
		public function get isUltimateSkill():Boolean
		{
			return ( _leftUseCount != -1 );
		}
		
		public function startBattle():void
		{
			if(isUltimateSkill)
			{
				useCount = getLevelValueByTag(template.baseUseCount);
			}
		}
		
		public function get useCount():int
		{
			return _leftUseCount;
		}
		
		public function set useCount(value:int):void
		{
			_leftUseCount = value;
		}
		
		public function get level():int
		{
			return _level;
		}
		
		public function set level(value:int):void
		{
			_level = value;
			updateMpCost();
			updateRange();
			updateDistance();
		}
		
		public function isMyTarget(value:IGameAvatar , targetType:String = "range_target"):Boolean
		{
			if(!value) return false;
			var t:int = targetType == "range_target" ? template.rangeTarget : template.target;
			switch(t)
			{
				case AvatarCampTypeKey.ME:
					if(value != this.owner.avatar) return false;
					break;
				case AvatarCampTypeKey.EMENY:
					if(owner.party != -1 && value.avatarValue.party != -1) return false;
					if(owner.party == -1 && value.avatarValue.party == -1) return false;
					break;
				case AvatarCampTypeKey.OWEN_WITH_OUT_ME:
					if(value == this.owner.avatar) return false;
					if(owner.party != -1 && value.avatarValue.party != 1 && value.avatarValue.party != 2) return false;
					if(owner.party == -1 && value.avatarValue.party != -1) return false;
					break;
				case AvatarCampTypeKey.OWEN:
					if(owner.party != -1 && value.avatarValue.party != 1 && value.avatarValue.party != 2) return false;
					if(owner.party == -1 && value.avatarValue.party != -1) return false;
					break;
				default:
					return false;
					break;
			}
			
			return true;
		}
		
		public function useSkill(value:Vector.<IAvatarValue>=null):void
		{
			if(isUltimateSkill)
			{
				useCount --;
				_lastUseRound = BattleManager.battleManager.currentRound;
				owner.dispatchEvent(new AvatarValueEvent(AvatarValueEvent.USE_ULTIMATE));
			}
			else
			{
				owner.mp -= mpCost;
			}
			if(immediateEffectValue) _immediateEffectValue.init(owner , this);
			for each(var v:IAvatarValue in value)
			{
				var baseDamageNum:Number = 0;
				var kill:Boolean = false;
				var _baseDamage:IDamageEffectValue = createBaseDamageValue();
				
				if(_baseDamage)
				{ 
					_baseDamage.init(owner , v , this);
					_baseDamage.effect();
					baseDamageNum = _baseDamage.damage;
					kill = _baseDamage.kill;
					_baseDamage.dispose();
				}
				var additionalEffectValue:IAdditionalEffectValue = createAdditionalValue();
				if(additionalEffectValue)
				{
					additionalEffectValue.init(owner , v , this , baseDamageNum , kill);
					additionalEffectValue.effect();
					additionalEffectValue.dispose();
				}
				var buffDebuffEffectValue:IBuffDebuffEffectValue = createBuffDebuffValue();
				if(buffDebuffEffectValue) buffDebuffEffectValue.init(owner , v , this , baseDamageNum);
			}
			if(immediateEffectValue) _immediateEffectValue.recover();
		}
		
		public function dispose():void
		{
			if(_immediateEffectValue)
			{
				_immediateEffectValue.dispose();
				_immediateEffectValue = null;
			}
			if(_logicEffectValue)
			{
				_logicEffectValue.dispose();
				_logicEffectValue = null;
			}
		}
		
		protected var _level:int;
		
		protected var _template:SkillTemplateValue;
		
		protected var _leftUseCount:int;
		
		public function initlize(skillKeyStr:String, levelInt:int):void
		{
			_template = SkillTemplateValueList.getByKey(skillKeyStr);
			level = levelInt;
			if(int(_template.baseUseCount) == -1)
			{
				useCount = -1;
			}
			else
			{
				useCount = getLevelValueByTag(_template.baseUseCount);
				_coolingRound = getLevelValueByTag(_template.baseCoolingRound);
			}
		}
		
		protected function updateMpCost():void
		{
			_mpCost = getLevelValueByTag(_template.use_mp);
		}
		
		protected function updateRange():void
		{
			_rangeKey = getLevelValueByTag(_template.range);
		}
		
		protected function updateDistance():void
		{
			_distance = getLevelValueByTag(_template.distance);
		}
		
		public function get name():String
		{
			return template.name;
		}
		
		public function get desc():String
		{
			return template.desc;
		}
		
		public function get icon():String
		{
			return template.icon;
		}
		
		public function get demo():String
		{
			return template.demo;
		}
		
		public function getLevelValueByTag(value:String):*
		{
			if(value.indexOf("{") == -1) return value;
			return  template.getLevelValue(level).params.param.(@key == value).@key_value;
		}
		
		protected function getBuffProValue(value:String):Number
		{
			var xv:* = template.buffs.*.(@pro_name == value);
			if(xv)
			{
				if(String(xv.@num).indexOf("{") == -1)
				{
					return Number(xv.@num);
				}
				else
				{
					return Number( template.getLevelValue(level).params.param.(@key == xv.@num).@key_value );
				}
			}
			
			return 0;
		}
		
		protected function createBaseDamageValue():IDamageEffectValue
		{
			if(template.baseDamageValue)
			{
				var classRef:Class = getDefinitionByName(template.baseDamageValue.classRef) as Class;
				return new classRef() as IDamageEffectValue;
			}
			
			return null;
		}
		
		protected function createAdditionalValue():IAdditionalEffectValue
		{
			if(template.additional)
			{
				var classRef:Class = getDefinitionByName(template.additional.classRef) as Class;
				
				return new classRef() as IAdditionalEffectValue;
			}
			
			return null;
		}
		
		protected function createBuffDebuffValue():IBuffDebuffEffectValue
		{
			if(template.buffDebuff)
			{
				var classRef:Class = getDefinitionByName(template.buffDebuff.classRef) as Class;
				return new classRef() as IBuffDebuffEffectValue;
			}
			
			return null;
		}
		
		protected var _immediateEffectValue:IImmediateEffectValue;
		
		public function get immediateEffectValue():IImmediateEffectValue
		{
			if(!_immediateEffectValue && template.immediate)
			{
				var classClass:Class = getDefinitionByName(template.immediate.classRef) as Class;
				_immediateEffectValue = new classClass() as IImmediateEffectValue;
			}
			
			return _immediateEffectValue;
		}
		
		
		public function checkSkillHasLogic(value:String):Boolean
		{
			if(logicEffectValue)
			{
				return ( logicEffectValue.type == value );
			}
			
			return false;
		}
		
		protected var _logicEffectValue:ILogicEffectValue;
		
		public function get logicEffectValue():ILogicEffectValue
		{
			if(!_logicEffectValue && _template.logic)
			{
				var classClass:Class = getDefinitionByName(template.logic.classRef) as Class;
				_logicEffectValue = new classClass() as ILogicEffectValue;
				_logicEffectValue.init(this);
			}
			
			return _logicEffectValue;
		}
		
		/**
		 *  生命值
		 * @return 
		 * 
		 */	
		[Prop(mapping="maxHP")]
		public function get maxHP():Number
		{
			return getBuffProValue("maxHP");
		}
		
		/**
		 *  能量值
		 * @return 
		 * 
		 */	
		[Prop(mapping="initMP")]
		public function get initMP():Number
		{
			return getBuffProValue("initMP");
		}
		
		/**
		 *  能量恢复效率
		 * @return 
		 * 
		 */	
		[Prop(mapping="mpRecover")]
		public function get mpRecover():Number
		{
			return getBuffProValue("mpRecover");
		}
		
		/**
		 *  战斗
		 * @return 
		 * 
		 */	
		[Prop(mapping="normalPower")]
		public function get normalPower():Number
		{
			return getBuffProValue("normalPower");
		}
		
		/**
		 *  特技
		 * @return 
		 * 
		 */	
		[Prop(mapping="skillPower")]
		public function get skillPower():Number
		{
			return getBuffProValue("skillPower");
		}
		
		/**
		 *  元素
		 * @return 
		 * 
		 */	
		[Prop(mapping="elementPower")]
		public function get elementPower():Number
		{
			return getBuffProValue("elementPower");
		}
		
		/**
		 *  物理防御
		 * @return 
		 * 
		 */	
		[Prop(mapping="normalDefense")]
		public function get normalDefense():Number
		{
			return getBuffProValue("normalDefense");
		}
		
		/**
		 *  技能防御
		 * @return 
		 * 
		 */	
		[Prop(mapping="skillDefense")]
		public function get skillDefense():Number
		{
			return getBuffProValue("skillDefense");
		}
		
		/**
		 *  元素防御
		 * @return 
		 * 
		 */	
		[Prop(mapping="elementDefense")]
		public function get elementDefense():Number
		{
			return getBuffProValue("elementDefense");
		}
		
		/**
		 *  普通攻击力
		 * @return 
		 * 
		 */	
		[Prop(mapping="normalDamage")]
		public function get normalDamage():Number
		{
			return getBuffProValue("normalDamage");
		}
		
		/**
		 *  特技攻击力
		 * @return 
		 * 
		 */	
		[Prop(mapping="skillDamage")]
		public function get skillDamage():Number
		{
			return getBuffProValue("skillDamage");
		}
		
		/**
		 *  元素攻击力
		 * @return 
		 * 
		 */	
		[Prop(mapping="elementDamage")]
		public function get elementDamage():Number
		{
			return getBuffProValue("elementDamage");
		}
		
		/**
		 *  移动力
		 * @return 
		 * 
		 */	
		[Prop(mapping="moveCapability")]
		public function get moveCapability():Number
		{
			return getBuffProValue("moveCapability");
		}
		
		/**
		 *  命中等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="hitRate")]
		public function get hitRate():Number
		{
			return getBuffProValue("hitRate");
		}
		
		/**
		 *  闪避等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="dodgeRate")]
		public function get dodgeRate():Number
		{
			return getBuffProValue("dodgeRate");
		}
		
		/**
		 *  穿透等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="penetrateRate")]
		public function get penetrateRate():Number
		{
			return getBuffProValue("penetrateRate");
		}
		
		/**
		 *  抵抗等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="resistRate")]
		public function get resistRate():Number
		{
			return getBuffProValue("resistRate");
		}
		
		/**
		 *  强攻等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="enforceRate")]
		public function get enforceRate():Number
		{
			return getBuffProValue("enforceRate");
		}
		
		/**
		 *  抵挡等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="blockRate")]
		public function get blockRate():Number
		{
			return getBuffProValue("blockRate");
		}
		
		/**
		 *  抵挡力
		 * @return 
		 * 
		 */		
		[Prop(mapping="blockEffect")]
		public function get blockEffect():Number
		{
			return getBuffProValue("blockEffect");
		}
		
		/**
		 *  强韧等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="toughness")]
		public function get toughness():Number
		{
			return getBuffProValue("toughness");
		}
		
		/**
		 *  暴击等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="critRate")]
		public function get critRate():Number
		{
			return getBuffProValue("critRate");
		}
		
		/**
		 *  暴击伤害加成
		 * @return 
		 * 
		 */		
		[Prop(mapping="critEffect")]
		public function get critEffect():Number
		{
			return getBuffProValue("critEffect");
		}
		
		/**
		 *  御体等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="defenseRate")]
		public function get defenseRate():Number
		{
			return getBuffProValue("defenseRate");
		}
		
		/**
		 *  压制等级
		 * @return 
		 * 
		 */		
		[Prop(mapping="suppressRate")]
		public function get suppressRate():Number
		{
			return getBuffProValue("suppressRate");
		}
		
		/**
		 *  压制力
		 * @return 
		 * 
		 */	
		[Prop(mapping="suppressEffect")]
		public function get suppressEffect():Number
		{
			return getBuffProValue("suppressEffect");
		}
		
		/**
		 *  先攻值
		 * @return 
		 * 
		 */		
		[Prop(mapping="actRate")]
		public function get actRate():Number
		{
			return getBuffProValue("actRate");
		}
		
		public static function create(str:SkillTemplateValue , owner:IAvatarValue , level:int , slot:int , leftUseCount:int = -1):SkillValue
		{
			var classClass:Class = getDefinitionByName(str.dynamicRef) as Class;
			var returnV:SkillValue = new classClass() as SkillValue;
			returnV.owner = owner;
			returnV.initlize(str.key , level);
			returnV._slot = slot;
			return returnV;
		}
	}
}